#include "CAnimals.h"
#include <stdio.h>

CAnimalFactory AnimalFactory;

CAnimal::CAnimal()
{
    AnimalFactory.LockServer(TRUE);
}

CAnimal::~CAnimal()
{
    AnimalFactory.LockServer(FALSE);
}

ULONG __stdcall CAnimal::XDog::AddRef()
{
    METHOD_PROLOGUE(CAnimal, Dog);
    return pThis->AddRef();
}

ULONG __stdcall CAnimal::XDog::Release()
{
    METHOD_PROLOGUE(CAnimal, Dog);
    return pThis->Release();
}

HRESULT __stdcall CAnimal::XDog::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CAnimal, Dog);
    return pThis->QueryInterface(iid, ppvObj);
}

HRESULT __stdcall CAnimal::XDog::Call(void)
{
    printf("Woof\r\n");
    return S_OK;
}

ULONG __stdcall CAnimal::XCat::AddRef()
{
    METHOD_PROLOGUE(CAnimal, Cat);
    return pThis->AddRef();
}

ULONG __stdcall CAnimal::XCat::Release()
{
    METHOD_PROLOGUE(CAnimal, Cat);
    return pThis->Release();
}

HRESULT __stdcall CAnimal::XCat::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CAnimal, Cat);
    return pThis->QueryInterface(iid, ppvObj);
}

HRESULT __stdcall CAnimal::XCat::Call(void)
{
    printf("Meow\r\n");
    return S_OK;
}

ULONG __stdcall CAnimal::XPig::AddRef()
{
    METHOD_PROLOGUE(CAnimal, Pig);
    return pThis->AddRef();
}

ULONG __stdcall CAnimal::XPig::Release()
{
    METHOD_PROLOGUE(CAnimal, Pig);
    return pThis->Release();
}

HRESULT __stdcall CAnimal::XPig::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CAnimal, Pig);
    return pThis->QueryInterface(iid, ppvObj);
}

HRESULT __stdcall CAnimal::XPig::Call(void)
{
    printf("Oink\r\n");
    return S_OK;
}


CAnimalFactory::CAnimalFactory() : m_nLockTick(0)
{
}

CAnimalFactory::~CAnimalFactory()
{
}

HRESULT __stdcall CAnimalFactory::CreateInstance(IN IUnknown* pUnkOuter, IN REFIID riid, OUT void** ppvObject)
{
    CAnimal* lpAnimal = new CAnimal;
    return lpAnimal->QueryInterface(riid, ppvObject);
}

HRESULT __stdcall CAnimalFactory::LockServer(IN BOOL fLock)
{
    if (fLock)
    {
        InterlockedIncrement(&m_nLockTick);
    }
    else
    {
        if (m_nLockTick > 0)
            InterlockedDecrement(&m_nLockTick);
    }

    return S_OK;
}
